//UL Collision Engine
//By: Desconocido

//complete new think() function with player boundaries

#include <oslib/oslib.h>
#include "overworld.h"

#define SCREENW         480
#define SCREENH         272
#define MAPWIDTH		64
#define MAPHEIGHT		64
#define TILESIZE		16

#define PLAYERHEIGHT	45
#define PLAYERWIDTH		30

#define VELMOVING		2


OSL_MAP *currentMap;
OSL_IMAGE *mapTileset;
void *mapOrig;
int hMapT;
int wMapT;
int Tile[MAPWIDTH*MAPHEIGHT];
int tileS = 16;
int scrollx,scrolly;
int x, y;
int h, w;

struct cTile
{
    bool		solid;
    cTile()
    {
		solid = false;
	};
};

class cMap
{
    public:
            void loadMap();
            void drawMap();
            void loadCollisions();
            void loadNonCollisions();
            void declareMap(OSL_MAP *mapName, OSL_IMAGE *mTileset, void *mapFunc, int mapHieght, int mapWidth);
            void limitScroll();
            bool colmapxy(int x, int y)
            {
                    return tiles[x][y].solid;
            }
    private:
            cTile tiles[MAPWIDTH][MAPHEIGHT];
};


class cPlayer
{
    public:
            void think();
            void boundaries();

            cPlayer();

            bool collision_ver(int x, int y, int &tilecoordx);
            bool collision_hor(int x, int y, int &tilecoordy);
    private:
		int velx, vely;
		int tilecoordx, tilecoordy;
};

cPlayer player;
cMap map;

void cMap::declareMap(OSL_MAP *mapName, OSL_IMAGE *mTileset, void *mapFunc, int mapHieght, int mapWidth)
{
    if(!mTileset)
        oslDebug("An unidentified tileset has been called");
    currentMap = mapName;
    mapTileset = mTileset;
    mapOrig = mapFunc;
    hMapT = mapHieght;
    wMapT = mapWidth;
}

void cMap::loadMap()
{
    currentMap = oslCreateMap(
    mapTileset,
    mapOrig,
    tileS,tileS,
    hMapT,wMapT,
    OSL_MF_U16);

}

void cMap::loadCollisions()
{
    for(int i=0;i<MAPWIDTH;i++)
    {
            Tile[i] = 1;
    }
}

void cMap::loadNonCollisions()
{
    Tile[1] = 0;
    Tile[19] = 0;
    Tile[2] = 0;
    Tile[26] = 0;
}

void cMap::drawMap()
{
    oslDrawMapSimple(currentMap);
}

void cMap::limitScroll()
{
	if(currentMap->scrollX < 0)
	{
		currentMap->scrollX = 0;
		scrollx = 0;
	}

	else if(currentMap->scrollX+480 > wMapT*tileS)
	{
            currentMap->scrollX = (wMapT*tileS)-480;
            scrollx = 0;
	}


	if(currentMap->scrollY < tileS)
	{
		currentMap->scrollY = tileS;
		scrolly = 0;
	}

	else if(currentMap->scrollY + 272 > hMapT*tileS)
	{
            currentMap->scrollY = (hMapT*tileS)-272;
            scrolly = 0;
	}
}

//cPlayer class functions

cPlayer::cPlayer()
{
	x		= 0;
	y		= 16;

	h		= PLAYERHEIGHT;
	w		= PLAYERWIDTH;

	velx	= 0;
	vely	= 0;
}

bool cPlayer::collision_hor(int x, int y, int &tilecoordy)
{
	int tilexpixels = x-(x%16);
	int testend = x + w;

	tilecoordy = y/16;

	tilecoordx = tilexpixels/16;

	while(tilexpixels <= testend){
		if(Tile[*mapOrig[MAPWIDTH*tilecoordy+tilecoordx]] == 1)
			return true;
        else
        {
		tilecoordx++;
		tilexpixels+=16;
        }
	}

	return false;
}

bool cPlayer::collision_ver(int x, int y, int &tilecoordx)
{
	int tileypixels = y-(y%16);
	int testend = y + h;

	tilecoordx = x/16;

	tilecoordy = tileypixels/16;

	while(tileypixels <= testend){
		if(Tile[*mapOrig[MAPHEIGHT*tilecoordy+tilecoordx]] == 1)
			return true;

		tilecoordy++;
		tileypixels += 16;
	}

	return false;
}

void cPlayer::boundaries()
{

	int tx, ty;

	//Horizontal Map Boundaries
	if(currentMap->scrollX < 0) {
		if(x <= SCREENW/2) {
			tx = x - currentMap->scrollX;
			currentMap->scrollX = (x-(SCREENW/2));
		}
		else {
			currentMap->scrollX = 0;
			tx = x;
		}
	}
	else if(currentMap->scrollX > ((MAPWIDTH-(SCREENW/TILESIZE))*TILESIZE) ) {
		if(x <= SCREENW/2) {
			tx = x - currentMap->scrollX;
			currentMap->scrollX = (x-(SCREENW/2));
		}
		else {
			currentMap->scrollX = ((MAPWIDTH-(SCREENW/TILESIZE))*TILESIZE);
			tx = x;
		}
	}
	else {
		tx = x - currentMap->scrollX;
		currentMap->scrollX = (x-(SCREENW/2));
	}

	//Vertical Map Boundaries
	if(currentMap->scrollY < 0) {
		if(y <= SCREENH/2) {
			ty = y - currentMap->scrollY;
			currentMap->scrollY = (y-(SCREENH/2));
		}
		else {
			currentMap->scrollY = 0;
			ty = y;
		}
	}
	else if(currentMap->scrollY > ((MAPHEIGHT-(SCREENH/TILESIZE))*TILESIZE) ) {
		if(y <= SCREENW/2) {
			ty = y - currentMap->scrollY;
			currentMap->scrollY = (y-(SCREENH/2));
		}
		else {
			currentMap->scrollY = ((MAPHEIGHT-(SCREENH/TILESIZE))*TILESIZE);
			ty = y;
		}
	}
	else {
		ty = y - currentMap->scrollY;
		currentMap->scrollY = (y-(SCREENH/2));
	}

	//If map width is less than the screen's width, we default the scroll back to 0
	if(MAPWIDTH <= (SCREENW/TILESIZE))
		currentMap->scrollX = 0;
	if(MAPHEIGHT <= (SCREENH/TILESIZE))
		currentMap->scrollY = 0;

	tx = x;
	ty = y;
}


void cPlayer::think()
{
    velx= 0;
    vely= 0;
    int tilecoord;

    if(osl_keys->held.right)
    {
        velx = VELMOVING;
    }

    if(osl_keys->held.left)
    {
        velx = -VELMOVING;
    }

    if(osl_keys->held.up)
    {
        vely = -VELMOVING;
    }

    if(osl_keys->held.down)
    {
        vely = VELMOVING;
    }

//x axis player check
	if(velx > 0){
		if(collision_ver(x+velx+w, y, tilecoord))
			x = tilecoord*16 -w-1;
		else
			x += velx;
	}
	else if(velx < 0){
		if(collision_ver(x+velx, y, tilecoord))
			x = (tilecoord+1)*16 +1;
		else
			x += velx;
	}

//y axis player check
	if(vely < 0){
		if(collision_hor(x, y+vely, tilecoord))
			y = (tilecoord+1)*16 +1;
		else
			y += vely;
	}
	else if(vely > 0){
        if(collision_hor(x, y+vely+h, tilecoord))
			y = tilecoord*16 -h-1;
        else
            y += vely;
    }
}
